﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.IO;
using System.Linq;
using System.Windows.Forms;
using LumenWorks.Framework.IO.Csv;

namespace spSitePro.UndisposedObjectsFinder
{
    public partial class MainForm : Form
    {
        #region [Fields]

        private DataTable _results;

        #endregion

        #region [Constructors]

        public MainForm()
        {
            InitializeComponent();
            dgvResults.CellClick += Controls_dgvResults_CellClick;
            dgvResults.AutoGenerateColumns = false;
        }

        #endregion 

        #region [Event Handlers] 

        private void Controls_dgvResults_CellClick(object sender, DataGridViewCellEventArgs e)
        {
            if (e.ColumnIndex == 5)
            {
                MessageDetailsForm detailsForm = new MessageDetailsForm((string)_results.Rows[e.RowIndex]["Message"]);
                detailsForm.ShowDialog();
            }
        }

        private void Controls_btnRun_Click(object sender, EventArgs e)
        {
            ThreadParams threadParams = new ThreadParams
            {
                MessageToSearch = "An SPRequest object was not disposed before the end of this thread",
                Directory = textBox1.Text,
                StringsToExclude = richTextBox1.Text,
                SearchOptions = rbSONone.Checked
                                            ? SearchOptions.None
                                            : rbSOExclude.Checked
                                                ? SearchOptions.Exclude
                                                : rbSOInclude.Checked
                                                    ? SearchOptions.Include
                                                    : SearchOptions.None
            };

            BackgroundWorker bw = new BackgroundWorker();
            bw.WorkerReportsProgress = true;
            bw.DoWork += OnDoWork;
            bw.ProgressChanged += OnProgressChanged;
            bw.RunWorkerCompleted += OnWorkerCompleted;

            bw.RunWorkerAsync(threadParams);
        }

        private void OnWorkerCompleted(object sender, RunWorkerCompletedEventArgs args)
        {
            _results = (DataTable)args.Result;
            dgvResults.DataSource = _results;
            dgvResults.Invalidate(true);
        }

        private void OnProgressChanged(object sender, ProgressChangedEventArgs args)
        {
            pbWorkProgress.Value = args.ProgressPercentage;
            //pbWorkProgress.Text = "ddsfds";
            
            if (args.ProgressPercentage%25 == 0)
            {
                //MessageBox.Show(args.ProgressPercentage.ToString() + "   " + (args.ProgressPercentage % 25).ToString());
                dgvResults.DataSource = (DataTable) args.UserState;
                _results = (DataTable) args.UserState;
                dgvResults.Invalidate(true);
            }
        }

        private void OnDoWork(object sender, DoWorkEventArgs args)
        {
            BackgroundWorker bw = sender as BackgroundWorker;
            ThreadParams threadParams = (ThreadParams)args.Argument;
            
            String[] files = Directory.GetFiles(threadParams.Directory);

            IList<string> stringsToExclude = threadParams.StringsToExclude
                                                            .Split(new [] { '\n' }, StringSplitOptions.RemoveEmptyEntries)
                                                            .ToList();

            DataTable results = GenerateDataTable();

            int index = 0;
            int numberOfFilesProcessed = 0;

            foreach (string fileName in files)
            {
                DataRow row = null; 

                try
                {
                    if (fileName.IndexOf(".log") == -1)
                    {
                        continue;
                    }

                    using (FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read))
                    {
                        using (CsvReader csv = new CsvReader(new StreamReader(fs), true, '\t'))
                        {
                            while (csv.ReadNextRecord())
                            {
                                if (row != null)
                                {
                                    if (csv[C.LogFields.Timestamp].Last() == '*')
                                    {
                                        row[C.DataRow.Message] += csv[C.LogFields.Message].Substring(3);
                                    }
                                    else
                                    {
                                        if (threadParams.SearchOptions != SearchOptions.None)
                                        {
                                            string message = (string) row[C.DataRow.Message];

                                            bool isFound = stringsToExclude.Where(message.Contains).Any();

                                            if (isFound && threadParams.SearchOptions == SearchOptions.Include)
                                            {
                                                row[C.DataRow.Index] = ++index;
                                                results.Rows.Add(row);
                                            }

                                            if (!isFound && threadParams.SearchOptions == SearchOptions.Exclude)
                                            {
                                                row[C.DataRow.Index] = ++index;
                                                results.Rows.Add(row);
                                            }
                                        }
                                        else
                                        {
                                            row[C.DataRow.Index] = ++index;
                                            results.Rows.Add(row);
                                        }

                                        row[C.DataRow.Message] = FormatMessage((string)row[C.DataRow.Message]);
                                        row = null;
                                    }
                                }
                                else if (csv[C.LogFields.Category].Equals("Performance") &&
                                         csv[C.LogFields.Message].Contains(threadParams.MessageToSearch))
                                {
                                    row = results.NewRow();
                                    row[C.DataRow.Message] = csv[C.LogFields.Message].Substring(0, csv[C.LogFields.Message].Length - 3);

                                    row[C.DataRow.File] = fileName.Substring(fileName.LastIndexOf('\\'));
                                    row[C.DataRow.CorrelationId] = csv[C.LogFields.Correlation];
                                    row[C.DataRow.Date] = csv[C.LogFields.Timestamp];
                                }
                            }
                        }
                    }
                }
                catch(Exception ex)
                {
                    
                }

                int progress = Convert.ToInt32(++numberOfFilesProcessed/(double) files.Length*100);

                bw.ReportProgress(progress, results);
            }
            args.Result = results;
        }

        #endregion

        #region [Helpers]

        private DataTable GenerateDataTable()
        {
            DataTable results = new DataTable("Results");
            results.Columns.Add(C.DataRow.CorrelationId, typeof(string));
            results.Columns.Add(C.DataRow.Index, typeof(int));
            results.Columns.Add(C.DataRow.File, typeof(string));
            results.Columns.Add(C.DataRow.Message, typeof(string));
            results.Columns.Add(C.DataRow.Date, typeof(string));

            return results;
        }

        private string FormatMessage(string message)
        {
            return message.Replace(" at ", "\n at ");
        }

        #endregion 
    }
}
